use crate::triangle::Triangle;
use crate::Rasterizer;
use crate::Vector;
use crate::{Vec2f, Vec3f};

pub type FragShader = fn(&Rasterizer, &Triangle, [f32; 3]) -> Vec3f;
// TODO trait DeepShader {}

pub fn normal_shader(r: &Rasterizer, t: &Triangle, barycoor: [f32; 3]) -> Vec3f {
    let norms = t.payload.normals.as_ref().unwrap();
    let norm = norms
        .iter()
        .zip(barycoor)
        .map(|(&n, b)| n * b)
        .fold(Vec3f::zero(), |ac, c| ac + c)
        .normalize();
    (norm + Vec3f::one() / 2.0) * 255.
}
pub fn color_shader(r: &Rasterizer, t: &Triangle, barycoor: [f32; 3]) -> Vec3f {
    if let Some(color) = t.payload.colors {
        color
            .iter()
            .zip(barycoor.iter())
            .map(|(&a, &b)| a * b)
            .fold(Vec3f::zero(), |accum, cur| accum + cur)
    } else {
        panic!("Need Color Value")
    }
}
pub fn adjust_z(t: &Triangle, barycoor: [f32; 3]) -> f32 {
    println!("barycoor: {barycoor:?}");
    println!("zs in screen{:?}", t.positions.map(|p| p[2]));
    t.positions
        .map(|p| p[2].recip())
        .iter()
        .zip(barycoor)
        .map(|(a, b)| a * b)
        .fold(0.0, |ac, c| ac + c)
        .recip()
}
fn adjust_bary(t: &Triangle, barycoor: [f32; 3]) -> [f32; 3] {
    let z = adjust_z(t, barycoor);
    let paras = Vec3f::from(t.positions.map(|p| p[2].recip())) * Vec3f::from(barycoor) * z;
    println!("z = {z}");
    println!("paras = {paras:?}");
    paras.0
}
pub fn texture_shader(r: &Rasterizer, t: &Triangle, barycoor: [f32; 3]) -> Vec3f {
    if let Some(tex_coor) = t.payload.tex_coords {
        // let bary = adjust_bary(t, barycoor);
        // println!("Tex coor:{tex_coor:?}");
        let Vector([u, v]) = tex_coor
            .iter()
            .zip(barycoor)
            .map(|(&x, b)| x * b)
            .fold(Vec2f::zero(), |accum, cur| accum + cur);
        r.texture_img
            .as_ref()
            // .and_then(|t| Some(t.get_color_bilinear(1. - v, 1. - u))) //NOTE: 左手坐标系与右手坐标系？
            .and_then(|t| Some(t.get_color(1. - v, 1. - u)))
            // .and_then(|t| Some(Vec3f::from([255.0_f32, 255., 255.])))
            .expect("texture img")
    } else {
        panic!("Need Texture Value")
    }
}
